package com.iflytek.autofly.setting.biz.networking;

import android.content.Context;
import android.text.TextUtils;

import com.iflytek.autofly.bluetoothservice.aidl.RRBluetoothDevice;
import com.iflytek.autofly.bluetoothservice.util.BluetoothManager;
import com.iflytek.autofly.bluetoothservice.util.BluetoothServiceCons;
import com.iflytek.autofly.bluetoothservice.util.IBluetoothSettingListener;
import com.iflytek.autofly.setting.R;
import com.iflytek.autofly.utils.FlyAssert;
import com.iflytek.autofly.utils.FlyLog;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

/**
 * <b>Description: </b>蓝牙管理器<br/>
 * <b>Change History:</b><br/>
 * <table border="1">
 * <tr>
 * <td><b>user</b></td>
 * <td><b>date</b></td>
 * <td><b>time</b></td>
 * <td><b>reason</b></td>
 * </tr>
 * <tr>
 * <td>JunLuan@iflytek.com</td>
 * <td>2015年5月26日</td>
 * <td>上午10:40:06</td>
 * <td>创建此文件</td>
 * </tr>
 * <tr>
 * <td>junluan@iflytek.com</td>
 * <td>2015年6月19日</td>
 * <td>下午2:58:00</td>
 * <td>基于统一的蓝牙服务重构代码</td>
 * </tr>
 * </table>
 *
 * @author JunLuan@iflytek.com
 */
public class FlyBluetoothManager {


    private static final String TAG = "FlyBluetoothManager";
    private BluetoothManager mBluetooth;
    private IBtConnectStateUpdater mBtUpdater;
    private Context mContext;
    private IBluetoothSettingListener mListener;

    private FlyBluetoothManager() {
    }

    public static FlyBluetoothManager getInstance() {
        return FlyBluetoothManagerInstance.INSTANCE;
    }

    private static String platformState2String(int state) {
        switch (state) {
            case BluetoothServiceCons.ConnectionStatus.CONNECTION_UNPAIRED:
                return "UNPAIRED" + state;
            case BluetoothServiceCons.ConnectionStatus.CONNECTION_CONNECTED:
                return "CONNECTED" + state;
            case BluetoothServiceCons.ConnectionStatus.CONNECTION_CONNECT_FAILED:
                return "CONNECT_FAILED" + state;
            case BluetoothServiceCons.ConnectionStatus.CONNECTION_CONNECTING:
                return "CONNECTING" + state;
            case BluetoothServiceCons.ConnectionStatus.CONNECTION_DISCONNECT:
                return "DISCONNECT" + state;
            default:
                return "UNKNOWN" + state;
        }

    }

    public void init(Context context, IBtConnectStateUpdater u) {
        FlyLog.d(TAG, "in");
        FlyAssert.flyAssert(context != null);

        if (context == mContext) {
            FlyLog.d(TAG, "out");
            return;
        }

        if (mContext != null) {
            fini();
        }

        mContext = context;
        mBtUpdater = u;

        if (mListener == null) {
            mListener = new IBluetoothSettingListener() {

                @Override
                public void onA2DPConnectStatus(int serviceStatus) {
                }

                @Override
                public void onDeviceListChanged(List<RRBluetoothDevice> list) {
                    int size = -1;
                    if (list != null) {
                        size = list.size();
                    }
                    FlyLog.d(TAG, "onDeviceListChanged:[" + size + "]");
                    if (mBtUpdater != null) {
                        mBtUpdater.onListChanged();
                    }
                }

                @Override
                public void onConnectStatus(RRBluetoothDevice rrBluetoothDevice) {
                    if (rrBluetoothDevice != null) {
                        FlyLog.d(TAG, "onConnectStatus [" + rrBluetoothDevice.getName() + "]" + "[" + platformState2String(rrBluetoothDevice.getState()) + "]");
                        if (mBtUpdater != null) {
                            mBtUpdater.onStatusChanged(rrBluetoothDevice, rrBluetoothDevice.getState());
                        }
                    } else {
                        FlyLog.e(TAG, "rrBluetoothDevice null");
                    }

                }

                @Override
                public void onServiceStatusChanged(int status) {
                    switch (status) {
                        case BluetoothServiceCons.AidlStatus.SERVICE_AIDL_BINDING:
                            FlyLog.i(TAG, "SERVICE_AIDL_BINDING");
                            break;
                        case BluetoothServiceCons.AidlStatus.SERVICE_AIDL_BOUND:
                            FlyLog.i(TAG, "SERVICE_AIDL_BOUND");
                            if (mBtUpdater != null) {
                                mBtUpdater.onServiceBound();
                            }
                            break;
                        case BluetoothServiceCons.AidlStatus.SERVICE_AIDL_NOT_BOUND:
                            FlyLog.i(TAG, "SERVICE_AIDL_NOT_BOUND");
                            mBluetooth = null;
                            break;
                        default:
                            FlyLog.e(TAG, "unknown status [" + status + "]");
                            break;
                    }
                }

                @Override
                public void onScanStart() {
                    FlyLog.d(TAG, "enter");
                    if (mBtUpdater != null) {
                        mBtUpdater.onScanStart();
                    }
                }

                @Override
                public void onScanEnd() {
                    FlyLog.d(TAG, "enter");
                    if (mBtUpdater != null) {
                        mBtUpdater.onScanEnd();
                    }
                }

                @Override
                public void onDeviceFound(final RRBluetoothDevice rrBluetoothDevice) {
                    if (rrBluetoothDevice != null) {
                        FlyLog.d(TAG, "[" + rrBluetoothDevice.getName() + "]");
                        if (mBtUpdater != null) {
                            new Thread(new Runnable() {
                                @Override
                                public void run() {
                                    if (mBtUpdater != null) {
                                        mBtUpdater.onDeviceFound(rrBluetoothDevice);
                                    }
                                }
                            }).start();
                        }
                    } else {
                        FlyLog.e(TAG, "rrBluetoothDevice null");
                    }


                }
            };
        }

        FlyLog.d(TAG, "registerListener");
        mBluetooth = BluetoothManager.registerListener(mContext, mListener,
                BluetoothServiceCons.ClientType.CLIENT_TYPE_SETTING);

        FlyAssert.flyAssert(mBluetooth != null, "mBluetooth != null");
        FlyLog.d(TAG, "out");
    }

    public void fini() {
        FlyLog.d(TAG, "in");

        if (mBluetooth != null) {
            mBluetooth.stopScan();
            FlyLog.d(TAG, "destroyClient");
            mBluetooth.destroyClient();
        }
        // destroy had already call unregister
        // BluetoothManager.unregisterListener(mListener,
        // BluetoothServiceCons.ClientType.CLIENT_TYPE_SETTING);
        mBluetooth = null;
        mListener = null;
        mBtUpdater = null;
        mContext = null;
        FlyLog.d(TAG, "out");
    }

    /**
     * getBluetoothName:获取蓝牙名称. <br/>
     *
     * @return
     */
    public String getName() {
        FlyAssert.flyAssert(mBluetooth != null, "mBluetooth != null");
        if (mBluetooth != null) {
            String name = mBluetooth.getName();
            if (TextUtils.isEmpty(name)) {
                return "";
            }
            return name;
        }
        FlyLog.e(TAG, "mBluetooth not ready");
        return "";
    }

    /**
     * setName:设置蓝牙名称. <br/>
     *
     * @param name
     */
    public void setName(String name) {
        if (TextUtils.isEmpty(name)) {
            FlyLog.w(TAG, "name empty.");
            return;
        }
        if (getName().equals(name)) {
            FlyLog.w(TAG, "same name.");
            return;
        }

        FlyAssert.flyAssert(mBluetooth != null, "mBluetooth != null");

        if (mBluetooth != null) {
            mBluetooth.changeName(name);
        }

    }

    /**
     * getPin:获取pin码名称. <br/>
     *
     * @return
     */
    public String getPin() {
        FlyAssert.flyAssert(mBluetooth != null, "mBluetooth != null");
        if (mBluetooth != null) {
            String pin = mBluetooth.getPIN();
            if (TextUtils.isEmpty(pin)) {
                return "";
            }
            return pin;
        }
        return "";
    }

    /**
     * setPin:设置pin码名称. <br/>
     *
     * @param pin
     */
    public void setPin(String pin) {
        if (TextUtils.isEmpty(pin)) {
            FlyLog.w(TAG, "pin empty.");
            return;
        }
        if (getPin().equals(pin)) {
            FlyLog.w(TAG, "same pin.");
            return;
        }

        FlyAssert.flyAssert(mBluetooth != null, "mBluetooth != null");
        if (mBluetooth != null) {
            mBluetooth.changePIN(pin);
        }
    }

    public String getCurrnetDeviceName() {
        FlyAssert.flyAssert(mBluetooth != null, "mBluetooth != null");
        if (mBluetooth != null) {
            RRBluetoothDevice device = mBluetooth.getCurrentDevice();
            if (device != null && device.getState() == BluetoothServiceCons.ConnectionStatus.CONNECTION_CONNECTED) {
                return device.getName();
            }
        }
        return null;
    }

    /**
     * getDeviceList:获取设备列表. <br/>
     *
     * @return
     */
    public ArrayList<RRBluetoothDevice> getDeviceList() {
        FlyAssert.flyAssert(mBluetooth != null, "mBluetooth != null");

        List<RRBluetoothDevice> serviceList = null;
        if (mBluetooth != null) {
            serviceList = mBluetooth.getDeviceList();
        }

        ArrayList<RRBluetoothDevice> list = new ArrayList<RRBluetoothDevice>();

        int size = -1;
        if (serviceList != null) {
            size = serviceList.size();
        }
        FlyLog.d(TAG, "list size:[" + size + "]");

        for (int i = 0; i < size; i++) {
            RRBluetoothDevice serviceDevice = serviceList.get(i);
            if (i == 0) {
                serviceDevice.setState(mBluetooth.getConnectionState());
            }
            list.add(serviceDevice);
        }
        return list;
    }

    public void restoreDefault(Context context) {
        final CyclicBarrier barrier = new CyclicBarrier(2);
        init(context, new IBtConnectStateUpdater() {
            @Override
            public void onStatusChanged(RRBluetoothDevice rrDevice,
                                        int changeState) {
            }

            @Override
            public void onListChanged() {
            }

            @Override
            public void onServiceBound() {
                if (mContext != null) {
                    setName(mContext.getResources().getString(
                            R.string.net_bt_default_name));
                    clearList();
                    try {
                        barrier.await();
                    } catch (InterruptedException e) {
                        FlyLog.e(TAG, e);
                        fini();
                    } catch (BrokenBarrierException e) {
                        FlyLog.e(TAG, e);
                        fini();
                    }
                }
            }

            @Override
            public void onScanStart() {
            }

            @Override
            public void onScanEnd() {
            }

            @Override
            public void onDeviceFound(RRBluetoothDevice rrBluetoothDevice) {
            }
        });
        try {
            barrier.await();
        } catch (InterruptedException e) {
            FlyLog.e(TAG, e);
        } catch (BrokenBarrierException e) {
            FlyLog.e(TAG, e);
        }

        fini();

    }

    /**
     * connect:连接<i>"bean"</i>指点的设备. <br/>
     *
     * @param bean
     */
    public void connect(BtDeviceBean bean) {
        FlyAssert.flyAssert(mBluetooth != null, "mBluetooth != null");
        FlyLog.d(TAG, bean.getName() + "," + bean.getAddr());
        mBluetooth.connectDevice(bean.getAddr());

    }

    /**
     * unpair:取消和<i>"bean"</i>指点的设备的配对. <br/>
     *
     * @param bean
     */
    public void unpair(BtDeviceBean bean) {
        FlyAssert.flyAssert(mBluetooth != null, "mBluetooth != null");
        FlyLog.d(TAG, bean.getName() + "," + bean.getAddr());
        mBluetooth.unPairDevice(bean.getAddr());
    }

    /**
     * cancelConnect:取消连接<i>"bean"</i>指点的设备. <br/>
     *
     * @param bean
     */
    public void cancelConnect(BtDeviceBean bean) {
        FlyAssert.flyAssert(mBluetooth != null, "mBluetooth != null");
        FlyLog.d(TAG, bean.getName() + "," + bean.getAddr());
        mBluetooth.disconnectDevice(bean.getAddr());

    }

    private void clearList() {
        FlyAssert.flyAssert(mBluetooth != null, "mBluetooth != null");
        if (mBluetooth != null) {
            List<RRBluetoothDevice> list = mBluetooth.getDeviceList();
            if (list != null) {
                for (RRBluetoothDevice bean : list) {
                    mBluetooth.unPairDevice(bean.getAddress());
                }
            }
        }
    }

    public void startScan() {
        FlyLog.d(TAG, "enter");
        FlyAssert.flyAssert(mBluetooth != null);
        if (mBluetooth != null) {
            mBluetooth.stopScan();
            mBluetooth.startScan();
        }
    }

    public boolean getAutoConnect() {
        FlyLog.d(TAG, "enter");
        FlyAssert.flyAssert(mBluetooth != null);
        if (mBluetooth != null) {
            return mBluetooth.getAutoConnectEnableState() == 1;
        }
        return true;
    }

    public void setAutoConnect(boolean autoConnect) {
        FlyLog.d(TAG, "enter");
        FlyAssert.flyAssert(mBluetooth != null);
        mBluetooth.setAutoConnectEnable(autoConnect);
    }

    public void stopScan() {
        if (mBluetooth != null) {
            mBluetooth.stopScan();
        }
    }

    /**
     * <b>Description: </b>蓝牙连接状态更新的回调<br/>
     * <b>Change History:</b><br/>
     * <table border="1">
     * <tr>
     * <td><b>user</b></td>
     * <td><b>date</b></td>
     * <td><b>time</b></td>
     * <td><b>reason</b></td>
     * </tr>
     * <tr>
     * <td>JunLuan@iflytek.com</td>
     * <td>2015年5月26日</td>
     * <td>上午11:18:58</td>
     * <td>创建此文件</td>
     * </tr>
     * <tr>
     * <td>junluan@iflytek.com</td>
     * <td>2015年6月19日</td>
     * <td>下午2:58:00</td>
     * <td>基于统一的蓝牙服务重构代码</td>
     * </tr>
     * </table>
     *
     * @author JunLuan@iflytek.com
     */
    public interface IBtConnectStateUpdater {

        /**
         * onStatusChanged:改变连接状态时回调. <br/>
         *
         * @param device 改变状态的设备
         * @param status 改变的状态
         */
        void onStatusChanged(final RRBluetoothDevice device,
                             final int status);

        /**
         * onListChanged:列表更新时回调. <br/>
         */
        void onListChanged();

        /**
         * onServiceBound:service成功bind时回调. <br/>
         */
        void onServiceBound();

        void onScanStart();

        void onScanEnd();

        void onDeviceFound(RRBluetoothDevice rrBluetoothDevice);
    }

    /**
     * @author JunLuan@iflytek.com
     */
    private static class FlyBluetoothManagerInstance {
        private static final FlyBluetoothManager INSTANCE = new FlyBluetoothManager();
    }
}
